/**
 * @license
 * Copyright Alibaba.com All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
 */

import {
  AfterContentInit,
  ContentChildren,
  Directive,
  ElementRef,
  EventEmitter,
  Input,
  OnChanges,
  OnDestroy,
  OnInit,
  Optional,
  Output,
  QueryList,
  SimpleChanges,
  SkipSelf
} from '@angular/core';

import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

import {
  InputBoolean,
  ApesDirectionVHIType,
  ApesDropdownHigherOrderServiceToken,
  ApesMenuBaseService,
  ApesUpdateHostClassService
} from '@shared/apes/core';

import { ApesMenuItemDirective } from './apes-menu-item.directive';
import { ApesMenuServiceFactory } from './apes-menu.resolver';
import { ApesMenuService } from './apes-menu.service';
import { ApesSubmenuComponent } from './apes-submenu.component';

@Directive({
  selector: '[apes-menu]',
  exportAs: 'apesMenu',
  providers: [
    ApesUpdateHostClassService,
    ApesMenuService,
    {
      provide: ApesMenuBaseService,
      useFactory: ApesMenuServiceFactory,
      deps: [[new SkipSelf(), new Optional(), ApesDropdownHigherOrderServiceToken], ApesMenuService]
    }
  ]
})
export class ApesMenuDirective implements AfterContentInit, OnInit, OnChanges, OnDestroy {
  private destroy$ = new Subject();
  private cacheMode: ApesDirectionVHIType;
  private listOfOpenedNzSubMenuComponent: ApesSubmenuComponent[] = [];
  @ContentChildren(ApesMenuItemDirective, { descendants: true }) listOfNzMenuItemDirective: QueryList<
    ApesMenuItemDirective
  >;
  @ContentChildren(ApesSubmenuComponent, { descendants: true }) listOfNzSubMenuComponent: QueryList<ApesSubmenuComponent>;
  @Input() apesInlineIndent = 24;
  @Input() apesTheme: 'light' | 'dark' = 'light';
  @Input() apesMode: ApesDirectionVHIType = 'vertical';
  @Input() @InputBoolean() apesInDropDown = false;
  @Input() @InputBoolean() apesInlineCollapsed = false;
  @Input() @InputBoolean() apesSelectable = !this.apesMenuService.isInDropDown;
  @Output() readonly apesClick = new EventEmitter<ApesMenuItemDirective>();

  updateInlineCollapse(): void {
    if (this.listOfNzMenuItemDirective) {
      if (this.apesInlineCollapsed) {
        this.listOfOpenedNzSubMenuComponent = this.listOfNzSubMenuComponent.filter(submenu => submenu.apesOpen);
        this.listOfNzSubMenuComponent.forEach(submenu => submenu.setOpenState(false));
        this.apesMode = 'vertical';
      } else {
        this.listOfOpenedNzSubMenuComponent.forEach(submenu => submenu.setOpenState(true));
        this.listOfOpenedNzSubMenuComponent = [];
        this.apesMode = this.cacheMode;
      }
      this.apesMenuService.setMode(this.apesMode);
    }
  }

  setClassMap(): void {
    const prefixName = this.apesMenuService.isInDropDown ? 'apes-dropdown-menu' : 'apes-menu';
    this.apesUpdateHostClassService.updateHostClass(this.elementRef.nativeElement, {
      [`${prefixName}`]: true,
      [`${prefixName}-root`]: true,
      [`${prefixName}-${this.apesTheme}`]: true,
      [`${prefixName}-${this.apesMode}`]: true,
      [`${prefixName}-inline-collapsed`]: this.apesInlineCollapsed
    });
  }

  constructor(
    public elementRef: ElementRef,
    private apesMenuService: ApesMenuBaseService,
    private apesUpdateHostClassService: ApesUpdateHostClassService
  ) {}

  ngOnInit(): void {
    this.setClassMap();
    this.apesMenuService.menuItemClick$.pipe(takeUntil(this.destroy$)).subscribe(menu => {
      this.apesClick.emit(menu);
      if (this.apesSelectable) {
        this.listOfNzMenuItemDirective.forEach(item => item.setSelectedState(item === menu));
      }
    });
  }

  ngAfterContentInit(): void {
    this.cacheMode = this.apesMode;
    this.updateInlineCollapse();
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.apesInlineCollapsed) {
      this.updateInlineCollapse();
    }
    if (changes.apesInlineIndent) {
      this.apesMenuService.setInlineIndent(this.apesInlineIndent);
    }
    if (changes.apesInDropDown) {
      this.apesMenuService.isInDropDown = this.apesInDropDown;
    }
    if (changes.apesTheme) {
      this.apesMenuService.setTheme(this.apesTheme);
    }
    if (changes.apesMode) {
      this.apesMenuService.setMode(this.apesMode);
      if (!changes.apesMode.isFirstChange() && this.listOfNzSubMenuComponent) {
        this.listOfNzSubMenuComponent.forEach(submenu => submenu.setOpenState(false));
      }
    }
    if (changes.apesTheme || changes.apesMode || changes.apesInlineCollapsed) {
      this.setClassMap();
    }
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }
}
